package edu.gatech.cc.liam.geometry.linear;

import java.util.ArrayList;

import edu.gatech.cc.liam.geometry.linear.convexhull.QHalf;

public class ApproximateRecusiveEuclideanBall {
	ArrayList<Polytope> levelApproximations;
	
	public ApproximateRecusiveEuclideanBall() {
		levelApproximations = new ArrayList<Polytope>();
	}
	
	public static ApproximateRecusiveEuclideanBall  makeFullRecusive(int dims, int levels) {
		ApproximateRecusiveEuclideanBall r = new ApproximateRecusiveEuclideanBall();
		r.levelApproximations.add(Polytope.makeBounds(dims, -1.0, 1.0));
		for(int i=0; i<levels; i++){
			Polytope previousSet = r.levelApproximations.get(i);
			PointSet nextLevelNorms = previousSet.getExtremePoints();
			Polytope nextSet = new Polytope(nextLevelNorms, -1.0);
			nextSet.addAll(previousSet);
			r.levelApproximations.add(nextSet);
		}
		return r;
	}
	
	public static ApproximateRecusiveEuclideanBall  makeMax(int dims, int numPoints) {
		ApproximateRecusiveEuclideanBall r = new ApproximateRecusiveEuclideanBall();
		Polytope set = Polytope.makeBounds(dims, -1.0, 1.0);
		for(int i=0; i<numPoints; i++){
			PointSet nextLevelNorms = set.getExtremePoints();
			NPoint origin = new NPoint(dims, 0.0);
			NPoint farthestPoint = nextLevelNorms.getFarthestPoint(origin);
			//System.out.print(farthestPoint.distance(origin) + ", ");
			farthestPoint.normalize();
			set.add(new Halfspace(farthestPoint, -1.0));
		}
		System.out.println("");
		r.levelApproximations.add(set);
		return r;
	}

	public static void main(String[] args) {
		ApproximateRecusiveEuclideanBall ab = makeFullRecusive(5, 2);
		Polytope appHull = ab.levelApproximations.get(ab.levelApproximations.size()-1);
		System.out.println("Hull Size: " + appHull.size());
		System.out.println("Set Size: " + appHull.getExtremePoints().size());
//		for(Polytope c : ab.levelApproximations) {
//			System.out.println(c.toStringAxb());
//			compareCover(c);
//			System.out.println("");
//		}
	}
	
	static void compareCover(Polytope testHull) {
		PointSet verts = testHull.getExtremePoints();
		NPoint orig = new NPoint(new double[testHull.getDimensions()]);
		double maxDist = -1.0;
		double minDist = Double.MAX_VALUE;
		double avgDist = 0.0;
		for(NPoint p : verts) {
			double distance = p.distance(orig);
			maxDist = Math.max(maxDist, distance);
			minDist = Math.min(minDist, distance);
			avgDist += distance;
			//System.out.println("Pt: " + p + " Distance to O: " + distance);
		}
		avgDist /= verts.size();
		System.out.println("");
		
		System.out.println("Hull Size: " + testHull.size() + "  Max Distance from sphere: " + (maxDist-1.0) + "  Min Dist: " + (minDist-1.0) + "  Average Dist: " + (avgDist-1.0) );

		ApproximateEuclideanBall testBall = new ApproximateEuclideanBall(testHull.getDimensions(), maxDist-1.0);
		System.out.println("AEBall Size: " + testBall.size());
		Polytope testHullD = new Polytope(testBall, -1.0);
		System.out.println(testHullD.toStringAxb());
		verts = QHalf.qHalfspaceHull(testHullD);
		maxDist = -1.0;
		minDist = Double.MAX_VALUE;
		avgDist = 0.0;
		for(NPoint p : verts) {
			double distance = p.distance(orig);
			maxDist = Math.max(maxDist, distance);
			minDist = Math.min(minDist, distance);
			avgDist += distance;
			//System.out.println("Pt: " + p + " Distance to O: " + distance);
		}
		avgDist /= verts.size();
		System.out.println("Max Distance from sphere: " + (maxDist-1.0) + "  Min Dist: " + (minDist-1.0) + "  Average Dist: " + (avgDist-1.0) );


	}
	
}
